limit++; /* We add one because limit is inclusive. */
if ( (b & _SEGMENT_G) )
limit <<= 12;
- if ( ((base + limit) <= base) ||
- ((base + limit) > PAGE_OFFSET) )
+
+ if ( (b & (3<<10)) == 1 )
+ {
+ /*
+ * Grows-down limit check.
+ * NB. limit == 0xFFFFF provides no access (if G=1).
+ * limit == 0x00000 provides 4GB-4kB access (if G=1).
+ */
+ if ( (base + limit) > base )
+ {
+ limit = -(base & PAGE_MASK);
+ goto truncate;
+ }
+ }
+ else
{
- /* Need to truncate. Calculate and poke a best-effort limit. */
- limit = PAGE_OFFSET - base;
- if ( (b & _SEGMENT_G) )
- limit >>= 12;
- limit--;
- d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
- d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
+ /*
+ * Grows-up limit check.
+ * NB. limit == 0xFFFFF provides 4GB access (if G=1).
+ * limit == 0x00000 provides 4kB access (if G=1).
+ */
+ if ( ((base + limit) <= base) ||
+ ((base + limit) > PAGE_OFFSET) )
+ {
+ limit = PAGE_OFFSET - base;
+ truncate:
+ if ( !(b & _SEGMENT_G) )
+ goto bad; /* too dangerous; too hard to work out... */
+ limit = (limit >> 12) - 1;
+ d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
+ d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
+ }
}
good:
if ( ((base + limit) < PAGE_SIZE) && positive_access )
{
/* Flip to expands-up. */
- limit >>= 12;
- limit -= (-PAGE_OFFSET/PAGE_SIZE) + 2;
+ limit = PAGE_OFFSET - base;
goto flip;
}
}
if ( ((PAGE_OFFSET - (base + limit)) < PAGE_SIZE) && !positive_access )
{
/* Flip to expands-down. */
- limit >>= 12;
- limit += (-PAGE_OFFSET/PAGE_SIZE) + 0;
+ limit = -(base & PAGE_MASK);
goto flip;
}
}
return 0;
flip:
+ limit = (limit >> 12) - 1;
a &= ~0x0ffff; a |= limit & 0x0ffff;
b &= ~0xf0000; b |= limit & 0xf0000;
- b ^= 1 << 10;
+ b ^= 1 << 10; /* grows-up <-> grows-down */
/* NB. These can't fault. Checked readable above; must also be writable. */
table[2*idx+0] = a;
table[2*idx+1] = b;